import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
import seaborn as sns
from matplotlib.ticker import MaxNLocator
from matplotlib.font_manager import FontProperties

# 设置中文字体 - 解决中文显示问题
try:
    # 尝试使用系统支持的中文字体
    plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'KaiTi', 'Arial Unicode MS']
    plt.rcParams['axes.unicode_minus'] = False  # 正确显示负号
except:
    print("注意：中文字体设置可能未生效，请检查系统字体")

# 加载实验数据
df = pd.read_csv('parameter_results.csv')

# 计算综合评分 (RMSE和MAE权重40%，训练时间权重20%)
df['CompositeScore'] = (1/df['RMSE'])*0.4 + (1/df['MAE'])*0.4 + (1/df['TrainingTime'])*0.2

# 设置可视化风格
sns.set(style="whitegrid", font_scale=1.1)
plt.figure(figsize=(18, 14))

# 1. 神经元数量对性能的影响 (固定窗口=60, Dropout≈0.2)
ax1 = plt.subplot(3, 2, 1)
neuron_df = df[df['Window'] == 60].sort_values('Neurons1')
neuron_df['NeuronConfig'] = neuron_df.apply(lambda x: f"{x['Neurons1']}-{x['Neurons2']}", axis=1)

sns.barplot(x='NeuronConfig', y='RMSE', data=neuron_df, ax=ax1, color='skyblue')
ax1.set_title('神经元数量对预测精度的影响 (RMSE)', fontweight='bold', fontsize=14)
ax1.set_xlabel('神经元配置 (第一层-第二层)', fontsize=12)
ax1.set_ylabel('RMSE (越低越好)', fontsize=12)
for i, v in enumerate(neuron_df['RMSE']):
    ax1.text(i, v+1, f'{v:.1f}', ha='center', fontsize=10)

# 2. 时间窗口对性能的影响 (固定神经元=80-100, Dropout=0.2)
ax2 = plt.subplot(3, 2, 2)
window_df = df[(df['Neurons1'] == 80) & (df['Neurons2'] == 100) &
               (df['Dropout'] == 0.2)].sort_values('Window')

sns.lineplot(x='Window', y='RMSE', data=window_df, ax=ax2,
             marker='o', markersize=8, linewidth=2.5, color='royalblue')
ax2.set_title('时间窗口长度对预测精度的影响 (RMSE)', fontweight='bold', fontsize=14)
ax2.set_xlabel('时间窗口 (天)', fontsize=12)
ax2.set_ylabel('RMSE (越低越好)', fontsize=12)
ax2.xaxis.set_major_locator(MaxNLocator(integer=True))
for _, row in window_df.iterrows():
    ax2.text(row['Window'], row['RMSE']+1, f'{row["RMSE"]:.1f}', ha='center', fontsize=10)

# 3. Dropout率对性能的影响 (固定窗口=60, 神经元=80-100)
ax3 = plt.subplot(3, 2, 3)
dropout_df = df[(df['Window'] == 60) & (df['Neurons1'] == 80) &
                (df['Neurons2'] == 100)].sort_values('Dropout')

sns.scatterplot(x='Dropout', y='RMSE', size='CompositeScore', sizes=(100, 400),
                hue='Name', data=dropout_df, ax=ax3, palette='viridis', legend='brief')
ax3.set_title('Dropout率对预测精度的影响 (RMSE)', fontweight='bold', fontsize=14)
ax3.set_xlabel('Dropout率', fontsize=12)
ax3.set_ylabel('RMSE (越低越好)', fontsize=12)
ax3.legend(loc='upper left', bbox_to_anchor=(1, 1), title='模型名称')  # 将图例放在图表外部

for _, row in dropout_df.iterrows():
    ax3.text(row['Dropout'], row['RMSE']+3, f'{row["RMSE"]:.1f}', ha='center', fontsize=10)

# 4. 参数对训练时间的影响 - 修复警告
ax4 = plt.subplot(3, 2, 4)
# 明确指定hue参数并设置legend=False以修复警告
sns.barplot(x='Name', y='TrainingTime', hue='Name', data=df, ax=ax4,
            palette=sns.color_palette("Blues_d", n_colors=len(df)),
            legend=False, dodge=False)
ax4.set_title('不同参数配置的训练时间对比', fontweight='bold', fontsize=14)
ax4.set_xlabel('参数配置', fontsize=12)
ax4.set_ylabel('训练时间 (秒)', fontsize=12)
plt.xticks(rotation=15)  # 旋转X轴标签

for i, v in enumerate(df['TrainingTime']):
    ax4.text(i, v+2, f'{v:.1f}s', ha='center', fontsize=10)

# 5. 三维关系：神经元-窗口-精度
ax5 = plt.subplot(3, 2, (5,6))
scatter = sns.scatterplot(x='Neurons1', y='Window', size='CompositeScore',
                          hue='Dropout', data=df, ax=ax5,
                          palette='coolwarm', sizes=(50, 300))
ax5.set_title('神经元数量、时间窗口与Dropout的综合影响', fontweight='bold', fontsize=14)
ax5.set_xlabel('第一层神经元数量', fontsize=12)
ax5.set_ylabel('时间窗口 (天)', fontsize=12)
ax5.grid(True, linestyle='--', alpha=0.7)

# 添加性能标签
for i, row in df.iterrows():
    ax5.text(row['Neurons1']+1, row['Window']+0.5,
             f"RMSE:{row['RMSE']:.1f}\nTime:{row['TrainingTime']:.0f}s",
             fontsize=9, ha='left')

# 添加图例和标题
plt.suptitle('股票预测模型参数敏感性分析', fontsize=20, fontweight='bold', y=0.98)

# 调整布局，为图例留出空间
plt.tight_layout(rect=[0, 0, 1, 0.96])
plt.subplots_adjust(top=0.93, hspace=0.3, wspace=0.25)

# 保存图像
plt.savefig('stock_prediction_parameter_analysis.png', dpi=300, bbox_inches='tight')
plt.show()